﻿using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
using System.Threading.Tasks;
using System;

namespace TyMES.MidWare
{
    public class RateLimitFilter : IAsyncActionFilter
    {
        private readonly IMemoryCache memoryCache;
        private const int secondsToReset = 1;
        private const int maxRequestPerSecond = 50;

        public RateLimitFilter(IMemoryCache memoryCache)
        {
            this.memoryCache = memoryCache;
        }

        public Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            string removeIP = context.HttpContext.Connection.RemoteIpAddress?.ToString();
            if (removeIP == null)
            {
                return next();
            }
            string cacheKey = $"LastVisitTick_{removeIP}";

            var requestCount = memoryCache.GetOrCreate(cacheKey, entry =>
            {
                entry.SlidingExpiration = TimeSpan.FromSeconds(secondsToReset);
                entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(secondsToReset * 2); // 双倍时间，确保过期  
                return 0;
            });

            if (requestCount >= maxRequestPerSecond)
            {
                context.Result = new StatusCodeResult(StatusCodes.Status429TooManyRequests);
                return Task.CompletedTask;
            }
            else
            {
                memoryCache.Set(cacheKey, requestCount + 1, new MemoryCacheEntryOptions
                {
                    SlidingExpiration = TimeSpan.FromSeconds(secondsToReset)
                });
                return next();
            }

            /*
            long? lastTick = memoryCache.Get<long?>(cacheKey);
            if (lastTick == null || Environment.TickCount64 - lastTick > 1) 
            {
                memoryCache.Set(cacheKey, Environment.TickCount64, TimeSpan.FromSeconds(10));
                return next();
            }
            else
            {
                context.Result = new ContentResult { StatusCode = 429 };
                return Task.CompletedTask;
            }
            */
        }
    }
}
